#![allow(unused_imports,dead_code,unused_assignments)]
use axum::{
    extract::{Form, Query, Json, Request, Multipart, DefaultBodyLimit },
    routing::{get,post},
    response::Response,
    body::{ Bytes},
    response::IntoResponse,
    Router
};
use crate::domain::GoodsQueryRequest;
use crate::domain::CustOrderBean;
use crate::domain::GoodsBean;
use crate::domain::OrderItemBean;
use crate::serviceimpl::goods_service::select_goods_by_recommend as service_select_goods_by_recommend;
use crate::serviceimpl::goods_service::find_goods_by_id as service_find_goods_by_id;
use crate::serviceimpl::goods_service::select_goods_by_goods_type_id as service_select_goods_by_goods_type_id;
use crate::serviceimpl::goods_service::count_active_goodses_by_goods_type_id as service_count_active_goodses_by_goods_type_id;
use crate::serviceimpl::goods_service::list_active_goodses as service_list_active_goodses;
use crate::serviceimpl::goods_service::search_goods_by_page as service_search_goods_by_page;
use crate::serviceimpl::order_item_service::validate_order_items as service_validate_order_items;
use crate::serviceimpl::user_service::find_user_by_id as service_find_user_by_id;
use crate::serviceimpl::cust_order_service::commit_cust_order as service_commit_cust_order;
use serde::{Deserialize,Serialize};
use serde_json::{Value,Map};
use std::collections::HashMap;
use std::fs;
use std::sync::Mutex;
use tower_http::{trace::TraceLayer};

use tower_sessions::Session;
use chrono::{Local, DateTime};
use crate::utils::jwt_util::Claims;
use crate::utils::jwt_util::JWT_SECRET;
use jsonwebtoken::DecodingKey;
use jsonwebtoken::Validation;

lazy_static! {
	static ref TEMP_ORDER_ITEMS:Mutex<HashMap<String,Vec<OrderItemBean>>> = Mutex::new(HashMap::new());
}

pub fn store_goods(key:String,goods:GoodsBean, amount:i32) {
    let ret:Option<Vec<OrderItemBean>> = TEMP_ORDER_ITEMS.lock().unwrap().get(&key).cloned();
    if ret.is_none() {
       	let order_item = OrderItemBean{
           	id : 0,
           	name : "orderItem".to_string(),
           	active : true,
           	price : goods.price,
           	amount : amount,
           	goods_id : goods.id,
           	cust_order_id : 0,
        };
        let mut order_items = Vec::new();
        order_items.push(order_item);
        TEMP_ORDER_ITEMS.lock().unwrap().insert(key,order_items);
    } else {
        let mut order_items = ret.clone().expect("Reason");
        for order_item in &mut order_items.iter_mut() {
            if order_item.goods_id == goods.id {
                order_item.amount = order_item.amount + amount;
                TEMP_ORDER_ITEMS.lock().unwrap().insert(key,order_items);
                return
            }
        }
       	let order_item = OrderItemBean{
           	id : 0,
           	name : "orderItem".to_string(),
           	active : true,
           	price : goods.price,
           	amount : amount,
           	goods_id : goods.id,
           	cust_order_id : 0,
        };
        order_items.push(order_item);
        TEMP_ORDER_ITEMS.lock().unwrap().insert(key,order_items);
    }
}

pub fn pick_goods(key:String) -> Vec<OrderItemBean> {
	let ret:Option<Vec<OrderItemBean>> = TEMP_ORDER_ITEMS.lock().unwrap().get(&key).cloned();
	if ret.is_none() {
		return Vec::new();
	}
	let order_items = ret.clone().expect("Reason");
	return order_items;
}

pub fn remove_goods(key:String) {
	let ret:Option<Vec<OrderItemBean>> = TEMP_ORDER_ITEMS.lock().unwrap().get(&key).cloned();
	TEMP_ORDER_ITEMS.lock().unwrap().remove(&key);
}


#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IdsRequest {
	pub ids: String,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GoodsRecommendCustRequest {
	pub recommendTypeId: i64,
	pub page:i32,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BuyGoodsCustRequest {
	pub goodsId: i64,
	pub amount:i32,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CustOrderConfirmCustRequest {
    pub userName:String,
	pub phone:String,
	pub address:String,
	pub total:f64,
	pub payTypeId:i64,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GoodsSearchCustRequest {
    pub keyword:String,
	pub page:i32,
	pub rows:i32,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GoodsListCustRequest {
	pub goods_type_id: i64,
	pub page: i32,
}

pub fn goods_cust_controller() -> Router {
	Router::new()
	.route("/goods_list", post(goods_list))
	.route("/goods_search", post(goods_search))
	.route("/goodsrecommend_list", get(goodsrecommend_list))
	.route("/goods_buy", post(goods_buy))
	.route("/goods_lessen", post(goods_lessen))
	.route("/count_my_cart", post(count_my_cart))
	.route("/cart_list", post(cart_list))
	.route("/cust_order_submit", post(cust_order_submit))
	.route("/listActiveGoodses", post(list_active_goodses))
	.route("/cust_order_data_comfirm", post(cust_order_data_comfirm))
	.route("/cust_order_confirm", post(cust_order_comfirm))
}

pub async fn goods_list(Form(goods_list_cust_request):Form<GoodsListCustRequest>) ->String {
    let goods_type_id = goods_list_cust_request.goods_type_id;
    let page_number = goods_list_cust_request.page;
    let page_size = 8;
	let goodses = service_select_goods_by_goods_type_id(goods_type_id,page_number,page_size).await;
	let totalCount:i32 = service_count_active_goodses_by_goods_type_id(goods_type_id).await.unwrap().count_num as i32;
    let totalPage:i32 = (totalCount as f64/8.0).ceil() as i32;
	match goodses {
		Err(_) => {
			println!("Error!");
			r#"{  "rows": null,  "success": true}"#.to_string()
		},
		Ok(goodses) => {
			let json = serde_json::to_string_pretty(&goodses).unwrap();
			//println!("{}", json);

			let mut map = Map::new();
			map.insert("success".to_string(), Value::from(true));
			map.insert("pageNumber".to_string(), Value::from(page_number));
			map.insert("pageSize".to_string(), Value::from(8));
			map.insert("totalCount".to_string(), Value::from(totalCount));
			map.insert("totalPage".to_string(), Value::from(totalPage));
			map.insert(
				"rows".to_string(),
				serde_json::from_str(&json).unwrap(),
			);

			let resultjson = serde_json::to_string_pretty(&map).unwrap();
			//println!("{}", resultjson);
			return resultjson;
		}
	}
}

pub async fn goodsrecommend_list(Query(goods_recommend_cust_request):Query<GoodsRecommendCustRequest>) ->String {
    let recommend_type_id = goods_recommend_cust_request.recommendTypeId;
    let mut page_number = goods_recommend_cust_request.page;
    if page_number == 0 {
        page_number = 1;
    }
    let page_size = 8;
	let goodses = service_select_goods_by_recommend(recommend_type_id,page_number).await;
	match goodses {
		Err(_) => {
			println!("Error!");
			r#"{  "rows": null,  "success": true}"#.to_string()
		},
		Ok(goodses) => {
			let json = serde_json::to_string_pretty(&goodses).unwrap();
			//println!("{}", json);

			let mut map = Map::new();
			map.insert("success".to_string(), Value::from(true));
			map.insert("recommendTypeId".to_string(), Value::from(recommend_type_id));
			map.insert("page".to_string(), Value::from(page_number));
			map.insert(
				"rows".to_string(),
				serde_json::from_str(&json).unwrap(),
			);

			let resultjson = serde_json::to_string_pretty(&map).unwrap();
			//println!("{}", resultjson);
			return resultjson;
		}
	}
}

pub async fn goods_buy(mut session:Session,Json(buy_goods_cust_request):Json<BuyGoodsCustRequest>) -> String {
    let goods_id = buy_goods_cust_request.goodsId;
    let amount = buy_goods_cust_request.amount;
    let goods = service_find_goods_by_id(goods_id).await;
    match goods {
        Err(_) => {
			println!("Error!");
			r#"{  "rows": null,  "success": false}"#.to_string()
		},
        Ok(goods) => {
            if goods.stock > amount && goods.active == true {
                let mut order_items_key:String = session.get("orderItemsKey").await.unwrap() .unwrap_or_default();
                if order_items_key.is_empty() {
                    order_items_key = gen_order_items_key().await;
                    let _ = session.insert("orderItemsKey",order_items_key.clone()).await;
                }
                store_goods(order_items_key, goods, amount);
                r#"{  "rows": null,  "success": true}"#.to_string()
            } else {
                r#"{  "rows": null,  "success": false, "error": "存货不足。"}"#.to_string()
            }
        }
    }
}

pub async fn goods_lessen(mut session:Session,Json(buy_goods_cust_request):Json<BuyGoodsCustRequest>) -> String {
    let goods_id = buy_goods_cust_request.goodsId;
    let amount = buy_goods_cust_request.amount;
    let goods = service_find_goods_by_id(goods_id).await;
    match goods {
        Err(_) => {
			println!("Error!");
			r#"{  "rows": null,  "success": false}"#.to_string()
		},
        Ok(goods) => {
            if goods.active == true {
                let order_items_key:String = session.get("orderItemsKey").await.unwrap().unwrap_or_default();
                if order_items_key.is_empty() {
                    return r#"{  "rows": null,  "success": false, "error": "购物车没有货物。"}"#.to_string();
                }
                let mut order_items = pick_goods(order_items_key.clone());
                let mut index:usize = 0;
                for order_item in &mut order_items.iter_mut() {
                    if order_item.goods_id == goods.id {
                        if order_item.amount > amount {
                            order_item.amount = order_item.amount - amount;
                        } else if order_item.amount == amount {
                            order_items.remove(index);
                        } else {
                            return r#"{  "rows": null,  "success": false, "error": "购物车货品不足。"}"#.to_string();
                        }
                        TEMP_ORDER_ITEMS.lock().unwrap().insert(order_items_key.clone(),order_items);
                        return r#"{  "rows": null,  "success": true}"#.to_string();
                    }
                    let index = index + 1;
                }
                r#"{  "rows": null,  "success": false}"#.to_string()
            } else {
                r#"{  "rows": null,  "success": false, "error": "存货不足。"}"#.to_string()
            }
        }
    }
}

async fn gen_order_items_key() -> String {
    return "orderItemsKey".to_string();
}

pub async fn count_my_cart(session:Session) -> String {
    let order_items_key:String = session.get("orderItemsKey").await.unwrap().unwrap_or_default();
    if order_items_key.is_empty() {
        r#"{  "rows": 0,  "success": true}"#.to_string()
    } else {
        let order_items = pick_goods(order_items_key);
        let mut amount = 0;
        for order_item in order_items {
            amount = amount + order_item.amount;
        }
        let mut map = Map::new();
		map.insert("success".to_string(), Value::from(true));
		map.insert("rows".to_string(), Value::from(amount));
		let resultjson = serde_json::to_string_pretty(&map).unwrap();
		return resultjson;
    }
}

pub async fn cart_list(session:Session) -> String {
    let order_items_key:String = session.get("orderItemsKey").await.unwrap().unwrap_or_default();
    if order_items_key.is_empty() {
        r#"{  "rows": null,  "success": true}"#.to_string()
    } else {
        let order_items = pick_goods(order_items_key);
        let mut amount = 0;
        let mut total = 0.0;
        for order_item in &order_items {
            total = total + order_item.price * order_item.amount as f64;
        }
        let json = serde_json::to_string_pretty(&order_items).unwrap();

        let mut map = Map::new();
		map.insert("success".to_string(), Value::from(true));
		map.insert("total".to_string(), Value::from(total));
		map.insert(
			"rows".to_string(),
			serde_json::from_str(&json).unwrap(),
		);
		let resultjson = serde_json::to_string_pretty(&map).unwrap();
		return resultjson;
    }
}

pub async fn list_active_goodses() ->String {
	let goodses = service_list_active_goodses().await;
	match goodses {
		Err(_) => {
			println!("Error!");
			r#"{  "rows": null,  "success": true}"#.to_string()
		},
		Ok(goodses) => {
			let json = serde_json::to_string_pretty(&goodses).unwrap();
			//println!("{}", json);

			let mut map = Map::new();
			map.insert("success".to_string(), Value::from(true));
			map.insert(
				"rows".to_string(),
				serde_json::from_str(&json).unwrap(),
			);

			let resultjson = serde_json::to_string_pretty(&map).unwrap();
			//println!("{}", resultjson);
			return resultjson;
		}
	}
}

pub async fn cust_order_submit(Query(params):Query<HashMap<String, String>>,session:Session, req: Request) -> String {
    let order_items_key:String = session.get("orderItemsKey").await.unwrap().unwrap_or_default();
    if order_items_key.is_empty() {
        r#"{  "rows": null,  "success": false, "error": "未购买商品！" }"#.to_string()
    } else {
        let mut _token:String = "".to_string();
        if let Some(value) = params.get("token") {
            _token = value.clone();
        } else {
            if let Some(session_value) = session.get("token").await.unwrap() {
                _token = session_value;
            } else {
                let headers = req.headers();
                _token = headers.get("X-Token").unwrap().to_str().unwrap().to_string();
            }
        }
    	if _token.is_empty() {
       		return r#"{  "rows": null,  "success": false, "error": "请登录后，再提交订单！" }"#.to_string();
    	}
    	let claims:Claims = jsonwebtoken::decode(
    		&_token,
    		&DecodingKey::from_secret(JWT_SECRET.as_bytes()),
    		&Validation::default(),
    	)
    	.map(|data| data.claims).unwrap();
    	let user = service_find_user_by_id(claims.sub).await;
        match user {
            Err(_) => {
    			println!("Error!");
    			r#"{  "rows": null,  "success": false, "error": "请登录后，再提交订单！"}"#.to_string()
    		},
            Ok(user) => {
                let order_items = pick_goods(order_items_key);
                if service_validate_order_items(order_items).await.unwrap() {
                    r#"{  "rows": null,  "success": true }"#.to_string()
                } else {
                    r#"{  "rows": null,  "success": false, "error": "存货不足！"}"#.to_string()
                }
            }
        }
    }
}

pub async fn cust_order_data_comfirm(Query(params):Query<HashMap<String, String>>,session:Session, req: Request) -> String {
    let order_items_key:String = session.get("orderItemsKey").await.unwrap().unwrap_or_default();
    if order_items_key.is_empty() {
        r#"{  "rows": null,  "success": false, "error": "未购买商品！" }"#.to_string()
    } else {
        let mut _token:String = "".to_string();
        if let Some(value) = params.get("token") {
            _token = value.clone();
        } else {
            if let Some(session_value) = session.get("token").await.unwrap() {
                _token = session_value;
            } else {
                let headers = req.headers();
                _token = headers.get("X-Token").unwrap().to_str().unwrap().to_string();
            }
        }
    	if _token.is_empty() {
       		return r#"{  "rows": null,  "success": false, "error": "请登录后，再提交订单！" }"#.to_string();
    	}
    	let claims:Claims = jsonwebtoken::decode(
    		&_token,
    		&DecodingKey::from_secret(JWT_SECRET.as_bytes()),
    		&Validation::default(),
    	)
    	.map(|data| data.claims).unwrap();
    	let user = service_find_user_by_id(claims.sub).await;
        match user {
            Err(_) => {
    			println!("Error!");
    			r#"{  "rows": null,  "success": false, "error": "请登录后，再提交订单！"}"#.to_string()
    		},
            Ok(user) => {
                let user_json = serde_json::to_string_pretty(&user).unwrap();
                let order_items = pick_goods(order_items_key);
                let mut total = 0.0;
                let mut amount = 0;
                for order_item in &order_items {
                    total = total + order_item.price * order_item.amount as f64;
                    amount = amount + order_item.amount;
                }
                if amount == 0 {
                    return r#"{  "rows": null,  "success": false, "error": "不能提交空订单！"}"#.to_string();
                }
                let mut map = Map::new();
          		map.insert("success".to_string(), Value::from(true));
          		map.insert("total".to_string(), Value::from(total));
          		map.insert(
         			"user".to_string(),
         			serde_json::from_str(&user_json).unwrap(),
          		);
          		let resultjson = serde_json::to_string_pretty(&map).unwrap();
          		return resultjson;
            }
        }
    }
}

pub async fn cust_order_comfirm(session:Session,Query(params):Query<HashMap<String, String>>,Json(cust_order_confirm_cust_request):Json<CustOrderConfirmCustRequest>) -> String {
    let order_items_key:String = session.get("orderItemsKey").await.unwrap() .unwrap_or_default();
    if order_items_key.is_empty() {
        r#"{  "rows": null,  "success": false, "error": "未购买商品！" }"#.to_string()
    } else {
        let mut _token:String = "".to_string();
        if let Some(value) = params.get("token") {
            _token = value.clone();
        } else {
            if let Some(session_value) = session.get("token").await.unwrap() {
                _token = session_value;
            }
        }
    	if _token.is_empty() {
       		return r#"{  "rows": null,  "success": false, "error": "请登录后，再提交订单！" }"#.to_string();
    	}
    	let claims:Claims = jsonwebtoken::decode(
    		&_token,
    		&DecodingKey::from_secret(JWT_SECRET.as_bytes()),
    		&Validation::default(),
    	)
    	.map(|data| data.claims).unwrap();
    	let user = service_find_user_by_id(claims.sub).await;
        match user {
            Err(_) => {
    			println!("Error!");
    			r#"{  "rows": null,  "success": false, "error": "请登录后，再提交订单！"}"#.to_string()
    		},
            Ok(user) => {
                let user_name = cust_order_confirm_cust_request.userName;
                let phone = cust_order_confirm_cust_request.phone;
                let address = cust_order_confirm_cust_request.address;
                let mut total = cust_order_confirm_cust_request.total;
                let pay_type_id = cust_order_confirm_cust_request.payTypeId;
                let now = Local::now();
                let naiveNow = now.naive_local();

                let order_items = pick_goods(order_items_key.clone());
                let mut amount = 0;
                total = 0.0;
                for order_item in &order_items {
                    amount = amount + order_item.amount;
                    total = total + order_item.price * order_item.amount as f64;
                }

               	let cust_order = CustOrderBean{
                   	id : 0,
                   	name : "CustOrder".to_string(),
                   	active : true,
                   	total : total,
                   	amount : amount,
                   	status_id : 2,
                   	pay_type_id : pay_type_id,
                   	phone : phone,
                   	address : address,
                   	order_date_time : Some(naiveNow),
                   	user_id : user.id,
                };
                let success = service_commit_cust_order(cust_order,order_items).await.unwrap();
                if success == true {
                    remove_goods(order_items_key.clone());
                    r#"{  "rows": null,  "success": true , "message": "订单成功提交!" }"#.to_string()
                }else{
                    r#"{  "rows": null,  "success": false, "error": "订单提交失败！"}"#.to_string()
                }
            }
        }
    }
}

pub async fn goods_search(Json(goods_search_cust_request):Json<GoodsSearchCustRequest>) ->String {
    let keyword = goods_search_cust_request.keyword;
    let page_number = goods_search_cust_request.page;
    let page_size = goods_search_cust_request.rows;
	let goodses = service_search_goods_by_page(keyword,page_number,page_size).await;
	match goodses {
		Err(_) => {
			println!("Error!");
			r#"{  "rows": null,  "success": true}"#.to_string()
		},
		Ok(goodses) => {
			let json = serde_json::to_string_pretty(&goodses).unwrap();
			//println!("{}", json);

			let mut map = Map::new();
			map.insert("success".to_string(), Value::from(true));
			map.insert(
				"rows".to_string(),
				serde_json::from_str(&json).unwrap(),
			);

			let resultjson = serde_json::to_string_pretty(&map).unwrap();
			//println!("{}", resultjson);
			return resultjson;
		}
	}
}
